﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Savannah.Core
{
    /// <summary>
    /// Statikus osztály az állatok lépésére(mindkét állattípus mehet)
    /// </summary>
    static class AnimalMove
    {
        /// <summary>
        /// Kiválasztja az állat, hogy hova lépjen és végrehajtja a lépést
        /// </summary>
        /// <param name="pAnimal">az állat ami lépni fog</param>
        /// <param name="pMap">a komplett szavanna</param>
        static public void MoveExample(this AnimalBase pAnimal, Cell[,] pMap)
        {
            List<Cell> PossibleCells = new List<Cell>();
         //   Cell FromCell = pMap[pAnimal.xCoordinate, pAnimal.yCoordinate];

            int StartX = 0, StartY = 0, EndX=pMap.Length/2, EndY=EndX;

            if (pAnimal.xCoordinate - pAnimal.RangeOfView > StartX)
            {
                StartX = pAnimal.xCoordinate - pAnimal.RangeOfView;
            }

            if (pAnimal.yCoordinate - pAnimal.RangeOfView > StartY)
            {
                StartY = pAnimal.yCoordinate - pAnimal.RangeOfView;
            }

            if (pAnimal.yCoordinate + pAnimal.RangeOfView < StartX)
            {
                EndX = pAnimal.xCoordinate + pAnimal.RangeOfView;
            }

            if (pAnimal.yCoordinate + pAnimal.RangeOfView < StartY)
            {
                EndY = pAnimal.yCoordinate + pAnimal.RangeOfView;
            }


            int TempCoord = pAnimal.yCoordinate;

            for (int i = StartX; i < pAnimal.xCoordinate; ++i)
            {
                if (pMap[i, TempCoord].CellType == FieldType.water)
                {
                    continue;
                }
                PossibleCells.Add(pMap[i, TempCoord]);
            }

            for (int i = pAnimal.xCoordinate + 1; i < EndX; ++i)
            {
                if (pMap[i,TempCoord].CellType == FieldType.water)
                {
                    continue;
                }
                PossibleCells.Add(pMap[i, TempCoord]);
            }

            TempCoord = pAnimal.xCoordinate;

            for (int i = StartY; i < pAnimal.yCoordinate; ++i)
            {
                if (pMap[TempCoord, i].CellType == FieldType.water)
                {
                    continue;
                }
                PossibleCells.Add(pMap[TempCoord, i]);
            }

            for (int i = pAnimal.yCoordinate + 1; i < EndY; ++i)
            {
                if (pMap[TempCoord,i].CellType==FieldType.water)
                {
                    continue;
                }
                PossibleCells.Add(pMap[TempCoord, i]);
            }


            Cell ToCell = SwitchCell(PossibleCells, pAnimal);


            pAnimal.DoTheMove(ToCell, pMap);
        }

        /// <summary>
        /// A lépés végrehajtása(csak addig lép amíg a RengeOfMove engedi)
        /// </summary>
        /// <param name="pAnimal">az állat, amelyik lép</param>
        /// <param name="pTo">hova lépjen</param>
        /// <param name="pMap">a szavanna</param>
        static private void DoTheMove(this AnimalBase pAnimal, Cell pTo, Cell[,] pMap)
        {

            if (pAnimal.xCoordinate-pAnimal.RangeOfMove > pTo.CoordX) 
            {
                pMap[pAnimal.xCoordinate - pAnimal.RangeOfMove, pAnimal.yCoordinate].AddAnimal(pAnimal);
                pMap[pAnimal.xCoordinate, pAnimal.yCoordinate].RemoveAnimal(pAnimal);
                pAnimal.xCoordinate -= pAnimal.RangeOfMove;

                return;
            }

            if (pAnimal.xCoordinate + pAnimal.RangeOfMove < pTo.CoordX)
            {
                pMap[pAnimal.xCoordinate + pAnimal.RangeOfMove, pAnimal.yCoordinate].AddAnimal(pAnimal);
                pMap[pAnimal.xCoordinate, pAnimal.yCoordinate].RemoveAnimal(pAnimal);
                pAnimal.xCoordinate += pAnimal.RangeOfMove;

                return;
            }
           
            if (pAnimal.yCoordinate - pAnimal.RangeOfMove > pTo.CoordY)
            {
                pMap[pAnimal.xCoordinate, pAnimal.yCoordinate - pAnimal.RangeOfMove].AddAnimal(pAnimal);
                pMap[pAnimal.xCoordinate, pAnimal.yCoordinate].RemoveAnimal(pAnimal);
                pAnimal.yCoordinate -= pAnimal.RangeOfMove;

                return;
            }
            
            if (pAnimal.yCoordinate + pAnimal.RangeOfMove < pTo.CoordY)
            {
                pMap[pAnimal.xCoordinate, pAnimal.yCoordinate + pAnimal.RangeOfMove].AddAnimal(pAnimal);
                pMap[pAnimal.xCoordinate, pAnimal.yCoordinate].RemoveAnimal(pAnimal);
                pAnimal.yCoordinate += pAnimal.RangeOfMove;

                return;
            }


            pTo.AddAnimal(pAnimal);
            pMap[pAnimal.xCoordinate, pAnimal.yCoordinate].RemoveAnimal(pAnimal);
            pAnimal.xCoordinate = pTo.CoordX;
            pAnimal.yCoordinate = pTo.CoordY;
        }

        /// <summary>
        /// Cellát választ pontozásos alapon
        /// </summary>
        /// <param name="pPossibleCells">Ezekben a cellákban keresi a legjobbat</param>
        /// <param name="pAnimal">az az állat, amelyik meghívja ezt a függvényt(összehasonlítások miatt kell)</param>
        /// <returns></returns>
        static private Cell SwitchCell(List<Cell> pPossibleCells, AnimalBase pAnimal)
        {
            int MaxPoints = 0, Index = 0, AktPoints;

            for (int i = 0; i < pPossibleCells.Count; ++i)
            {
                if (pPossibleCells[i].GetAnimalList().Count >= 5 || pPossibleCells[i].GetAdultNumber() >= 2) continue;


                AktPoints = pPossibleCells[i].CalculatePoints(pAnimal);
                if (AktPoints > MaxPoints)
                {
                    MaxPoints = AktPoints;
                    Index = i;
                }
            }

            return pPossibleCells[Index];
        }

        /// <summary>
        /// kikalkulálja a cella pontjait
        /// </summary>
        /// <param name="pCell">a cella amit pontoz</param>
        /// <param name="pAnimal">ua. mint a meghívó függvény paraméterében van</param>
        /// <returns></returns>
        static private int CalculatePoints(this Cell pCell, AnimalBase pAnimal)
        {
            int TempPoints = 0;

            if (pCell.ContainsAnimalsForRep(pAnimal))
            {
                TempPoints += 40;
            }

            TempPoints += pCell.HowMuchCanEat(pAnimal);

            return TempPoints;
        }

        /// <summary>
        /// ellenőrzi az állat, hogy tud-e szaporodni
        /// </summary>
        /// <param name="pCell">ezen a cellán ellenőrzi az adott állat</param>
        /// <param name="pAnimal">a nemek és fajok összehasonlításához</param>
        /// <returns></returns>
        static private bool ContainsAnimalsForRep(this Cell pCell, AnimalBase pAnimal)
        {
            foreach (AnimalBase ActAnimal in pCell.GetAnimalList())
            {
                if (ActAnimal.GetType() == pAnimal.GetType() && ActAnimal.SexEnumProperty != 
                    pAnimal.SexEnumProperty && pCell.CellType == FieldType.land && pAnimal.CurrentAge >= 5)
                {
                    return true;
                }
            }

            return false;
        }
        
        /// <summary>
        /// mekkora az esélye az állatnak, hogy jóllakik
        /// </summary>
        /// <param name="pCell">ebben a cellában vizsgál</param>
        /// <param name="pAnimal">ez az állat(kell a hungerlevel miatt)</param>
        /// <returns></returns>
        static private int HowMuchCanEat(this Cell pCell, AnimalBase pAnimal)
        {
            if (pAnimal is Vegetarian)
            {
                if (pCell.Plantp != null)
                {
                    return 3* pCell.Plantp.PlantSize * pAnimal.HungerLevel;
                }
            }
            else
            {
                int temp = 0;
                foreach (AnimalBase item in pCell.GetAnimalList())
                {
                    if (item is Vegetarian)
                    {
                        temp += (200 - item.SurvivalRate)/10;
                    }
                    return temp * pAnimal.HungerLevel / 2;
                }
            }

            return 0;
        } 
    }
}
